package com.ali.ttt.netty.client.config;

import com.ali.ttt.netty.client.handler.LoginResponseHandler;
import com.ali.ttt.netty.common.config.NettyServerProperties;
import com.ali.ttt.netty.common.domain.ApiMessage;
import com.ali.ttt.netty.common.domain.Client;
import com.ali.ttt.netty.common.domain.Message;
import com.ali.ttt.netty.common.handler.InMessageHandler;
import com.ali.ttt.netty.common.utils.MessageUtil;
import com.alibaba.fastjson.JSONObject;
import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.PooledByteBufAllocator;
import io.netty.buffer.Unpooled;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.json.JsonObjectDecoder;
import io.netty.util.concurrent.GenericFutureListener;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Lazy;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.net.InetAddress;
import java.nio.charset.StandardCharsets;


/**
 * @author yuxl
 */
@Slf4j
@Data
@Component
@Lazy(false)
public class NettyClient {

    private String host;
    // 服务器端口
    private int port;
    private Channel channel;

    private GenericFutureListener<ChannelFuture> closeListener;

    private GenericFutureListener<ChannelFuture> connectedListener;

    private Bootstrap b;
    private EventLoopGroup g;

    @Resource
    private NettyServerProperties nettyServerProperties;

    @Resource
    private LoginResponseHandler loginResponseHandler;

    @Resource
    private InMessageHandler inMessageHandler;



    public NettyClient()
    {
        /**
         * 通过nio方式来接收连接和处理连接
         **/
        g = new NioEventLoopGroup();
    }
    /**
     * 连接
     */
    @Async("async-thread-pool")
    public void doConnect()
    {
        try
        {
            /**
             * 客户端的是Bootstrap，服务端的则是 ServerBootstrap。
             * 都是AbstractBootstrap的子类。
             */
            b = new Bootstrap();

            b.group(g);
            b.channel(NioSocketChannel.class);
            b.option(ChannelOption.SO_KEEPALIVE, true);
            b.option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT);
            b.remoteAddress(host, port);
            // 设置通道初始化
            b.handler(
                    new ChannelInitializer<SocketChannel>()
                    {
                        public void initChannel(SocketChannel ch)
                        {
                            ch.pipeline().addLast(new JsonObjectDecoder());
                            ch.pipeline().addLast(inMessageHandler);
//                            ch.pipeline().addLast(loginResponseHandler);
                        }
                    }
            );
            ChannelFuture f = b.connect();
            f.addListener(connectedListener);
            // 阻塞
            f.channel().closeFuture().sync();
        } catch (Exception e)
        {
            log.error("客户端连接失败!{}", e.getMessage(),e);
        }
    }


    public void sendMsg(ApiMessage message){
        Message<ApiMessage> msg = new Message<>();
        msg.setPath("/api");
        msg.setMsg(message);
        channel.writeAndFlush(Unpooled.copiedBuffer(JSONObject.toJSONString(msg), StandardCharsets.UTF_8));
    }


    public void close()
    {
        g.shutdownGracefully();
    }
}
